package de.tabuma.soap.logik;

import de.tabuma.soap.*;
import de.tabuma.soap.entity.wsdl.*;
import de.tabuma.soap.entity.xsd.*;
import de.tabuma.soap.entity.*;
import javax.xml.bind.*;
import javax.xml.datatype.*;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import java.net.*;
import javax.xml.namespace.QName;

/**
  * @author $Author: alefen $
  * @version $Revision: 1.1 $
  * @since $Date: 2009/12/30 02:53:55 $
 */
public class SoapFacade {

    private static final Logger log = Logger.getLogger(SoapFacade.class.getName());
    private static final Hashtable speicher = new Hashtable();

    /**
     * TODO
     * @param wsdl
     * @return
     */
    public static List<TMessage> getRequestMessages(TDefinitions wsdl) {
       List<TMessage> ergebnis = getMessages(wsdl);
       log.fine("getting messages from getMessages");
       if(ergebnis==null) return null;
       ArrayList<TMessage> arrayList = new ArrayList<TMessage>();
       for(int i=0;i<ergebnis.size();i++) {
           if(ergebnis.get(i).getName().indexOf("Request")!=-1) {
               arrayList.add(ergebnis.get(i));
               log.fine("adding "+ergebnis.get(i).getName()+" to request list");
           }
       }
       return arrayList;
    }

    /**
     *
     * @param wsdl
     * @return
     */
    public static List<TMessage> getMessages(TDefinitions wsdl) {
       ArrayList<TMessage> arrayList = new ArrayList<TMessage>();
       try {
           List myList = wsdl.getAnyTopLevelOptionalElement();
           log.finer("loading "+myList.size()+" top elements from wsdl file");
           Iterator myIt = myList.iterator();
           while(myIt.hasNext()) {
               Object myElement = myIt.next();
               if(myElement instanceof TMessage) {
                   TMessage tmessage = (TMessage) myElement;
                   arrayList.add((TMessage) myElement);
                   log.finer("adding "+tmessage.getName()+" to message list");
               }
           }
           if(arrayList.size()==0) {
               log.fine("no elements in the message list");
               return null;
           }
       }
       catch(Exception e) {
           log.warning(e.getMessage());
       }
       return arrayList;
    }

    /**
     *
     * @param tbinding
     * @return
     */
    public static List<Long> getBindingOperation(TBinding tbinding) {
        ArrayList<Long> myList = new ArrayList<Long>();
        List<Long> list = tbinding.getOperation();
        myList.addAll(list);
        return myList;
    }

    /**
     *
     * @param wsdl
     * @return
     */
    public static List<TBinding> getBinding(TDefinitions wsdl) {
        ArrayList<TBinding> arrayList = new ArrayList<TBinding>();
        List<Long> anyElementList = wsdl.getAnyTopLevelOptionalElement();
        for(int i=0;i<anyElementList.size();i++) {
           AnyElement anyElement = PMF.get(anyElementList.get(i), new AnyElement());
           Object object = anyElement.toObject();
           if(object instanceof TBinding) {
               arrayList.add((TBinding) object);
           }
        }
        return arrayList;
    }

    /**
     *
     * @param wsdl
     * @return
     */
    public static List<TPortType> getAllPortType(TDefinitions wsdl) {
        log.fine("getAllPortType");
        ArrayList<TPortType> list = new ArrayList<TPortType>();
        List<Long> myList = wsdl.getAnyTopLevelOptionalElement();
        log.finer("count of anytopleveloptionalelement:"+myList.size());
        for(int i=0;i<myList.size();i++) {
            Long anyElementId = myList.get(i);
            AnyElement anyElement = PMF.get(anyElementId, new AnyElement());
            Object object = anyElement.toObject();
            log.finer("checking whether "+object+" is TPortType");
            if(TPortType.class.isInstance(object)) {
                log.finer("Is TPortType");
                TPortType port = (TPortType) object;
                list.add(port);
            }
        }
        return list;
    }

    /**
     *
     * @param wsdl
     * @return
     */
    public static List<Long> getAllOperation(TDefinitions wsdl) {
        log.fine("getAllOperation");
        ArrayList<Long> list = new ArrayList<Long>();
        List<TPortType> porttypeList = getAllPortType(wsdl);
        Iterator<TPortType> portIterator = porttypeList.iterator();
        while(portIterator.hasNext()) {
            List<Long> list1 = portIterator.next().getOperation();
            log.fine(list1.toString());
            list.addAll(list1);
        }
        return list;
    }

    /**
     *
     * @param wsdl
     * @param messageName
     * @return
     */
    public static TMessage getMessage(TDefinitions wsdl,String messageName) {
        log.fine("checking all topleveloperationalelements of tdefinitions object. count:"+wsdl.getAnyTopLevelOptionalElement().size());
        for(int i=0;i<wsdl.getAnyTopLevelOptionalElement().size();i++) {
            AnyElement objekt = PMF.get(wsdl.getAnyTopLevelOptionalElement().get(i),new AnyElement());
            if(log.getLevel()==Level.FINE || log.getLevel()==Level.FINER || log.getLevel()==Level.FINEST) {
                log.fine("objekt:"+objekt.toObject());
            }
            if(TMessage.class.isInstance(objekt.toObject())) {
                TMessage message = (TMessage) objekt.toObject();
                log.fine("message:"+message.getName()+"/"+messageName);
                if(message.getName().equals(messageName)) {
                    return message;
                }
            }
        }
        return null;
    }

    /**
     *
     * @param wsdl
     * @param operationName
     * @return
     */
    public static String getInputParameter(TDefinitions wsdl, String operationName) {
        log.fine("find operation: "+operationName);
        List<TPortType> list = getAllPortType(wsdl);
        log.fine("count porttype list:"+list.size());
        for(int i=0;i<list.size();i++) {
            List<Long> operation = list.get(i).getOperation();
            log.fine("count operation list for porttype(name="+list.get(i).getName()+"):"+operation.size());
            for(int j=0;j<operation.size();j++) {
                Long operationId = operation.get(j);
                TOperation op = PMF.get(operationId, new TOperation());
                log.fine("operation "+op.getName());
                if(op.getName().equals(operationName)) {
                    log.fine(op.getName() + " is equal to "+operationName);
                    List<Long> restList = op.getRest();
                    log.fine("operation rest count: "+restList.size());
                    for(int l=0;l<restList.size();l++) {
                        Long anyElementId = restList.get(l);
                        AnyElement myObjekt = PMF.get(anyElementId, new AnyElement());
                        if(myObjekt.toObject() instanceof TParamInput) {
                            TParamInput param = (TParamInput) myObjekt.toObject();
                            log.fine("found tparaminput "+param.getMessage());
                            return param.getMessage();
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     *
     * @param wsdl
     * @param operationName
     * @return
     */
    public static String getOutputParameter(TDefinitions wsdl, String operationName) {
        log.fine("operationName:"+operationName);
        List<TPortType> list = getAllPortType(wsdl);
        for(int i=0;i<list.size();i++) {
            List<Long> operation = list.get(i).getOperation();
            for(int j=0;j<operation.size();j++) {
                TOperation operation1 = PMF.get(operation.get(j), new TOperation());
                log.fine(operation1.getName()+"/"+operationName);
                if(operation1.getName().equals(operationName)) {
                    List<Long> restList = operation1.getRest();
                    log.fine("restcount:"+restList.size());
                    for(int l=0;l<restList.size();l++) {
                        AnyElement anyElement = PMF.get(restList.get(l), new AnyElement());
                        Object object = anyElement.toObject();
                        log.fine(""+object);
                        if(object instanceof TParamOutput) {
                            TParamOutput tParam = (TParamOutput) object;
                            return tParam.getMessage();
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     *
     * @param wsdl
     * @param operationName
     * @return
     */
    public static String getDefaultParameter(TDefinitions wsdl, String operationName) {
        log.fine("operationName:"+operationName);
        List<TPortType> list = getAllPortType(wsdl);
        for(int i=0;i<list.size();i++) {
            List<Long> operation = list.get(i).getOperation();
            for(int j=0;j<operation.size();j++) {
                TOperation operation1 = PMF.get(operation.get(j), new TOperation());
                log.fine(operation1.getName()+"/"+operationName);
                if(operation1.getName().equals(operationName)) {
                    List<Long> restList = operation1.getRest();
                    log.fine("restcount:"+restList.size());
                    for(int l=0;l<restList.size();l++) {
                        AnyElement anyElement = PMF.get(restList.get(l), new AnyElement());
                        Object object = anyElement.toObject();
                        log.fine(""+object);
                        if(object instanceof TFault) {
                            TFault tFault = (TFault) object;
                            return tFault.getMessage();
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     *
     * @param wsdl
     * @param operationName
     * @return
     */
    public static List<Long> getPart(TDefinitions wsdl,String operationName) {
        List<TMessage> messageList = getMessages(wsdl);
        if(messageList==null) {
            return null;
        }

        String qname = getInputParameter(wsdl,operationName);
        QName qname1 = new QName(qname);
        ArrayList<Long> partList = new ArrayList<Long>();
        for(int i=0;i<messageList.size();i++) {
            if(messageList.get(i).getName().equals(qname1.getLocalPart())) {
                return messageList.get(i).getPart();
            }
        }
        return partList;
    }

    /**
     *
     * @param wsdl
     * @return
     */
    public static List<TTypes> getTypes(TDefinitions wsdl) {
        ArrayList<TTypes> arrayList = new ArrayList<TTypes>();
        for(int i=0;i<wsdl.getAnyTopLevelOptionalElement().size();i++) {
            AnyElement anyElement = (AnyElement) PMF.get(wsdl.getAnyTopLevelOptionalElement().get(i),new AnyElement());
            Object objekt = anyElement.toObject();
            if(TTypes.class.isInstance(objekt)) {
                arrayList.add((TTypes) objekt);
            }
        }
        return arrayList;
    }

    public static XsSchema loadXsSchema(XsImport xsImport) {
        XsSchema xsSchema = null;
        long startTime = Calendar.getInstance().getTimeInMillis();
        //if xsImport has already loaded XsSchema, then load it from db otherwise from url
        if(xsImport.getXsSchemaId()!=null && xsImport.getXsSchemaId()!=0) {
            xsSchema = PMF.get(xsImport.getXsSchemaId(), new XsSchema());
        }
        else {
            xsSchema = WsdlFactory.loadXsdUrl(xsImport.getSchemaLocation());
            xsImport.setXsSchemaId(xsSchema.getId1());
            PMF.doUpdate(xsImport);
        }
        return xsSchema;
    }

    /**
     * @param schemaList
     * @return
     */
    public static List<XsComplexType> getComplexType(List<XsSchema> schemaList) {
        ArrayList<XsComplexType> arrayList = new ArrayList<XsComplexType>();
        long startTime = Calendar.getInstance().getTimeInMillis();
        List<Long> anyElementList = SchemaFacade.getSubElementOfSchema(schemaList);
        for(int i=0;i<anyElementList.size();i++) {
            AnyElement anyElement = PMF.get(anyElementList.get(i),new AnyElement());
            Object obj = anyElement.toObject();

            log.fine("object:"+obj.toString());
            if(XsComplexType.class.isInstance(obj)) {
                arrayList.add((XsComplexType) obj);
            }
            if(XsImport.class.isInstance(obj)) {
                XsImport xsImport = (XsImport) obj;
                try {
                    String speicherText = "xsImport"+xsImport.getId1();
                    List<XsComplexType> complexTypeList = null;
                    if(speicher.get(speicherText)!=null) {
                        complexTypeList = (List<XsComplexType>) speicher.get(speicherText);
                        log.fine("test");
                    }
                    else {
                        XsSchema xsSchema = loadXsSchema(xsImport);
                        ArrayList<XsSchema> schemaXsdList = new ArrayList<XsSchema>();
                        schemaXsdList.add(xsSchema);
                        complexTypeList = getComplexType(schemaXsdList);
                        speicher.put(speicherText, complexTypeList);
                    }

                    arrayList.addAll(complexTypeList);
                }
                catch(Exception e) {
                    e.printStackTrace();
                }
            }

        }
        return arrayList;
    }

    /**
     * @param schemaList
     * @return
     */
    public static List<XsElement> getElement(List<XsSchema> schemaList) {
        ArrayList<XsElement> arrayList = new ArrayList<XsElement>();
        try {
            log.fine("schemaList:"+schemaList);
            List<Long> anyElementList = SchemaFacade.getSubElementOfSchema(schemaList);
            for(int i=0;i<anyElementList.size();i++) {
                AnyElement anyElement = PMF.get(anyElementList.get(i),new AnyElement());
                Object obj = anyElement.toObject();
                if(XsElement.class.isInstance(obj)) {
                    arrayList.add((XsElement) obj);
                }
                if(XsImport.class.isInstance(obj)) {
                    XsImport xsImport = (XsImport) obj;
                    try {
                        XsSchema xsSchema = loadXsSchema(xsImport);

                        ArrayList<XsSchema> schemaXsdList = new ArrayList<XsSchema>();
                        schemaXsdList.add(xsSchema);
                        List<XsElement> complexTypeList = getElement(schemaXsdList);
                        arrayList.addAll(complexTypeList);
                    }
                    catch(Exception e) {
                        log.warning(e.getMessage()+"/"+e.getCause()+"/"+e.getClass());
                        String warning = "";
                        for(int j=0;j<e.getStackTrace().length;j++) {
                            warning += e.getStackTrace()[j];
                        }
                        log.warning(warning);
                    }
                }
            }
        }
        catch(Exception e) {
            log.warning(e.getMessage()+"/"+e.getCause()+"/"+e.getClass());
            String warning = "";
            for(int j=0;j<e.getStackTrace().length;j++) {
                warning += e.getStackTrace()[j] + "\n";
            }
            log.warning(warning);
        }
        return arrayList;
    }
}
